package com.haoze.message.message;

import com.haoze.common.config.RedisUtil;
import com.haoze.common.utils.HttpConnectUtils;
import com.haoze.common.utils.IpAndPortUtil;
import com.haoze.common.utils.SpringContextHolder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Component
public class WebSocketHandler extends AbstractWebSocketHandler {
    /**
     * 存储sessionId和webSocketSession
     * 需要注意的是，webSocketSession没有提供无参构造，不能进行序列化，也就不能通过redis存储
     * 在分布式系统中，要想别的办法实现webSocketSession共享
     */
    private static Map<String, Map> userSessionMap = new ConcurrentHashMap<>();
    private static Map<String, WebSocketSession> sessionListMap = new ConcurrentHashMap<>();

    /**
     * webSocket连接创建后调用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        String ip = IpAndPortUtil.getLocalIP();
        // 获取参数
        String user = String.valueOf(session.getAttributes().get("user"));
        System.out.println(user + "-" + session.getRemoteAddress().getAddress());
        RedisUtil redisUtil = (RedisUtil) SpringContextHolder.getBean("redisUtil");
        //如果移动端在高速行驶的条件下，是否会更换自己的外网ip，并且进行重新连接？
        redisUtil.set(user + "-" + session.getRemoteAddress().getAddress(), ip, 60 * 60 * 2);
        Map<String, WebSocketSession> map = userSessionMap.get(user);
        if(null==map) map = new ConcurrentHashMap();
        map.put(session.getId(), session);
        userSessionMap.put(user, map);
    }

    /**
     * 接收到消息会调用
     */
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        if (message instanceof TextMessage) {

        } else if (message instanceof BinaryMessage) {

        } else if (message instanceof PongMessage) {

        } else {
            System.out.println("Unexpected WebSocket message type: " + message);
        }
        System.out.println("getMsg: " + message);
    }

    /**
     * 连接出错会调用
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) {
        String user = String.valueOf(session.getAttributes().get("user"));
        sessionListMap.remove(session.getId());
        userSessionMap.put(user, sessionListMap);
    }

    /**
     * 连接关闭会调用
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        String user = String.valueOf(session.getAttributes().get("user"));
        sessionListMap.remove(session.getId());
        userSessionMap.put(user, sessionListMap);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * 后端发送消息
     */
    public void sendMessage(String user,String message) {
        RedisUtil redisUtil = (RedisUtil) SpringContextHolder.getBean("redisUtil");
        Long date = new Date().getTime();
        boolean isSuc = redisUtil.setNx("account=" + user + "&msg=" + message+date, "GET LOCK",1, TimeUnit.SECONDS);
        if(!isSuc){
            return;
        }
        final Iterator values = ((HashSet) redisUtil.keys(user+"-*")).iterator();
        //如果查询redis之后，显示的ip不是本地ip，那么重新用httpclent调用指定服务器的接口重新发送
        StringBuffer whiteIps = new StringBuffer();
        while (values.hasNext()) {
            String ip = (String) redisUtil.get(String.valueOf(values.next()));
            System.out.println("ip发送消息：" + ip);
            if (whiteIps.toString().indexOf(ip) > -1) {
                continue;
            }
            if (!ip.equals(IpAndPortUtil.getLocalIP())) {
                whiteIps.append(ip);
                HttpConnectUtils.sendGet("http://" + ip + ":8117/socket/sendmsg", "account=" + user + "&msg=" + message);
            }
        }
        Map<String, WebSocketSession> sessions = userSessionMap.get(user);
        if (null == sessions) return;
        for (WebSocketSession socketSession : sessions.values()) {
            try {
                socketSession.sendMessage(new TextMessage(message));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
